import java.util.Arrays;

public class FoxStones {
	private static final long MOD = 1000000009;

	public int getCount(int N, int M, int[] sx, int[] sy) {
		int markedCount = sx.length;
		long[] distances = new long[N * M];
		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= M; j++) {
				int index = (i - 1) * M + j - 1;
				long hash = 0;
				for (int k = 0; k < markedCount; k++)
					hash = hash * 239 + Math.max(Math.abs(sx[k] - i), Math.abs(sy[k] - j));
				distances[index] = hash;
			}
		}
		Arrays.sort(distances);
		long[] factorials = new long[N * M + 1];
		factorials[0] = 1;
		for (int i = 1; i <= N * M; i++)
			factorials[i] = (factorials[i - 1] * i) % MOD;
		long last = distances[0];
		int lastIndex = 0;
		long result = 1;
		for (int i = 0; i < distances.length; i++) {
			if (last != distances[i]) {
				result = (result * factorials[i - lastIndex]) % MOD;
				lastIndex = i;
				last = distances[i];
			}
		}
		result = (result * factorials[distances.length - lastIndex]) % MOD;
		return (int) result;
	}


// BEGIN CUT HERE
	public static void main(String[] args) {
		if (args.length == 0) {
			FoxStonesHarness.run_test(-1);
		} else {
			for (int i=0; i<args.length; ++i)
				FoxStonesHarness.run_test(Integer.valueOf(args[i]));
		}
	}
// END CUT HERE
}

// BEGIN CUT HERE
class FoxStonesHarness {
	public static void run_test(int casenum) {
		if (casenum != -1) {
			if (runTestCase(casenum) == -1)
				System.err.println("Illegal input! Test case " + casenum + " does not exist.");
			return;
		}
		
		int correct = 0, total = 0;
		for (int i=0;; ++i) {
			int x = runTestCase(i);
			if (x == -1) {
				if (i >= 100) break;
				continue;
			}
			correct += x;
			++total;
		}
		
		if (total == 0) {
			System.err.println("No test cases run.");
		} else if (correct < total) {
			System.err.println("Some cases FAILED (passed " + correct + " of " + total + ").");
		} else {
			System.err.println("All " + total + " tests passed!");
		}
	}
	
	static boolean compareOutput(int expected, int result) { return expected == result; }
	static String formatResult(int res) {
		return String.format("%d", res);
	}
	
	static int verifyCase(int casenum, int expected, int received) { 
		System.err.print("Example " + casenum + "... ");
		if (compareOutput(expected, received)) {
			System.err.println("PASSED");
			return 1;
		} else {
			System.err.println("FAILED");
			System.err.println("    Expected: " + formatResult(expected)); 
			System.err.println("    Received: " + formatResult(received)); 
			return 0;
		}
	}

	static int runTestCase(int casenum) {
		switch(casenum) {
		case 0: {
			int N                     = 6;
			int M                     = 1;
			int[] sx                  = {3};
			int[] sy                  = {1};
			int expected__            = 4;

			return verifyCase(casenum, expected__, new FoxStones().getCount(N, M, sx, sy));
		}
		case 1: {
			int N                     = 2;
			int M                     = 2;
			int[] sx                  = {2};
			int[] sy                  = {1};
			int expected__            = 6;

			return verifyCase(casenum, expected__, new FoxStones().getCount(N, M, sx, sy));
		}
		case 2: {
			int N                     = 3;
			int M                     = 3;
			int[] sx                  = {1,2,3};
			int[] sy                  = {1,2,3};
			int expected__            = 8;

			return verifyCase(casenum, expected__, new FoxStones().getCount(N, M, sx, sy));
		}
		case 3: {
			int N                     = 12;
			int M                     = 34;
			int[] sx                  = {5,6,7,8,9,10};
			int[] sy                  = {11,12,13,14,15,16};
			int expected__            = 410850247;

			return verifyCase(casenum, expected__, new FoxStones().getCount(N, M, sx, sy));
		}

		// custom cases

/*      case 4: {
			int N                     = ;
			int M                     = ;
			int[] sx                  = ;
			int[] sy                  = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new FoxStones().getCount(N, M, sx, sy));
		}*/
/*      case 5: {
			int N                     = ;
			int M                     = ;
			int[] sx                  = ;
			int[] sy                  = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new FoxStones().getCount(N, M, sx, sy));
		}*/
/*      case 6: {
			int N                     = ;
			int M                     = ;
			int[] sx                  = ;
			int[] sy                  = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new FoxStones().getCount(N, M, sx, sy));
		}*/
		default:
			return -1;
		}
	}
}

// END CUT HERE
